/******************************************************************************
 * This file is part of libemb.
 *
 * libemb is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * libemb is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with libemb.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Project: Embedme
 * Author : FergusZeng
 * Email  : cblock@126.com
 * git	  : https://gitee.com/newgolo/embedme.git
 * Copyright 2014~2020 @ ShenZhen ,China
*******************************************************************************/
#ifndef __DEBUG_PRINT_H__
#define __DEBUG_PRINT_H__

#include "BaseType.h"
#include "Singleton.h"
#include "Thread.h"
#include "ThreadUtil.h"
#include "FileUtil.h"
#include "DateTime.h"
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdarg.h>
#include <iostream>
#include <typeinfo>
#include <thread>

#define USE_ROS_LOG 0
/**
 *  @file   Tracer.h   
 *  @brief  实现调试打印
 *  @note   打印等级高于当前等级的都能打印出来,如当前级别为1,则DBG(0)等级的信息不会被打印出来,大于等于当前等级的信息都能打印出来.默认为INFO(1)等级.
 */
#define BUILD_REL_VERSION			0	    /**< 打开后只打印ERR和REL级别的打印 */
//打印等级说明:只有大于或等于当前打印等级的消息才能被打印!

#define TRACE_LEVEL_DBG             0       /**< 用于调试信息的打印 */
#define TRACE_LEVEL_WARN            1       /**< 用于警告信息打印 */
#define TRACE_LEVEL_ERR             2       /**< 用于错误信息的打印 */
#define TRACE_LEVEL_INFO            3       /**< 用于提示信息的打印 */
#define TRACE_LEVEL_REL             4       /**< 用于普通信息的打印 */

/* __VA_ARGS__宏是C99标准定义的 */
#define PRINTF(fmt,...)     do{printf(fmt,##__VA_ARGS__);}while(0)	
/* linux标准错误字串 */
#define ERRSTR				(strerror(errno))
#define ERRMSG(err)			(strerror(err))

#define TRACE_D(fmt,arg...)         do{libemb::Tracer::getInstance().print(TRACE_LEVEL_DBG,"<D>" fmt,##arg);}while(0)
#define TRACE_E(fmt,arg...)         do{libemb::Tracer::getInstance().print(TRACE_LEVEL_ERR,"<E>" fmt,##arg);}while(0)
#define TRACE_W(fmt,arg...)         do{libemb::Tracer::getInstance().print(TRACE_LEVEL_WARN,"<W>" fmt,##arg);}while(0)
#define TRACE_I(fmt,arg...)         do{libemb::Tracer::getInstance().print(TRACE_LEVEL_INFO,"<I>" fmt,##arg);}while(0)
#define TRACE_R(fmt,arg...)         do{libemb::Tracer::getInstance().print(TRACE_LEVEL_REL,"<R>" fmt,##arg);}while(0)
#define TRACE_L(uid,fmt,arg...)     do{libemb::Tracer::getInstance().print(uid,"<L%d>" fmt,uid,##arg);}while(0)

#define TRACE_DBG(fmt,arg...)       {TRACE_D("%s,L%d:" fmt,__FUNCTION__,__LINE__,##arg);}   /**<调试信息打印 */
#define TRACE_WARN(fmt,arg...)      {TRACE_W("%s,L%d:" fmt,__FUNCTION__,__LINE__,##arg);}   /**<警告信息打印 */
#define TRACE_ERR(fmt,arg...)       {TRACE_E("%s,L%d:" fmt,__FUNCTION__,__LINE__,##arg);}   /**<错误信息打印 */
#define TRACE_INFO(fmt,arg...)      {TRACE_I("%s,L%d:" fmt,__FUNCTION__,__LINE__,##arg);}   /**<提示信息打印 */
#define TRACE_REL(fmt,arg...)       {TRACE_R("%s:" fmt,__FUNCTION__,##arg);}                /**<普通信息打印 */
#define TRACE_LOG(uid,fmt,arg...)   {TRACE_L(uid,"%s,L%d:" fmt,__FUNCTION__,__LINE__,##arg);} /**<日志信息打印(uid必须大于TRACE_LEVEL_REL) */

/* 带类名的级别打印(仅在C++类中可使用,需要this指针) */
#define TRACE_DBG_CLASS(fmt,arg...)     {TRACE_D("%s::%s,L%d:" fmt,this->className(),__FUNCTION__,__LINE__,##arg);} /**<调试信息打印(带类名) */
#define TRACE_WARN_CLASS(fmt,arg...)    {TRACE_W("%s::%s,L%d:" fmt,this->className(),__FUNCTION__,__LINE__,##arg);} /**<警告信息打印(带类名) */
#define TRACE_ERR_CLASS(fmt,arg...)     {TRACE_E("%s::%s,L%d:" fmt,this->className(),__FUNCTION__,__LINE__,##arg);} /**<错误信息打印(带类名) */
#define TRACE_INFO_CLASS(fmt,arg...)    {TRACE_I("%s::%s,L%d:" fmt,this->className(),__FUNCTION__,__LINE__,##arg);} /**<提示信息打印(带类名) */
#define TRACE_REL_CLASS(fmt,arg...)     {TRACE_R("%s::%s:" fmt,this->className(),__FUNCTION__,##arg);}              /**<普通信息打印(带类名) */
#define TRACE_LOG_CLASS(uid,fmt,arg...) {TRACE_L(uid,"%s::%s,L%d:" fmt,this->className(),__FUNCTION__,__LINE__,##arg);} /**<<日志信息打印(带类名,uid必须大于TRACE_LEVEL_REL) */

/* 下面的宏用于调试跟踪 */
#define TRACE_IF(condition)         do{if((condition)){TRACE_RED("if(%s)<@%s,L%d>",#condition,__FUNCTION__,__LINE__);};}while(0)
#define TRACE_IF_CLASS(condition)   do{if((condition)){TRACE_RED("if(%s)<@%s::%s,L%d>",#condition,this->className(),__FUNCTION__,__LINE__);};}while(0)
#define TRACE_NONE(fmt,arg...)
#define TRACE_ASSERT(condition)  (if(!(condition)){TRACE_ERR("Assert !!!");while(1){libemb::Thread::msleep(100);}})

/* 颜色打印 */
#define TRACE_RED(fmt,arg...)       do{libemb::Tracer::getInstance().print(TRACE_LEVEL_REL,"<R>\033[31m\033[1m" fmt "\033[0m",##arg);}while(0)
#define TRACE_GREEN(fmt,arg...)     do{libemb::Tracer::getInstance().print(TRACE_LEVEL_REL,"<R>\033[32m\033[1m" fmt "\033[0m",##arg);}while(0)
#define TRACE_YELLOW(fmt,arg...)    do{libemb::Tracer::getInstance().print(TRACE_LEVEL_REL,"<R>\033[33m\033[1m" fmt "\033[0m",##arg);}while(0)
#define TRACE_PINK(fmt,arg...)      do{libemb::Tracer::getInstance().print(TRACE_LEVEL_REL,"<R>\033[35m\033[1m" fmt "\033[0m",##arg);}while(0)
#define TRACE_CYAN(fmt,arg...)      do{libemb::Tracer::getInstance().print(TRACE_LEVEL_REL,"<R>\033[36m\033[1m" fmt "\033[0m",##arg);}while(0)

#if BUILD_REL_VERSION
#include "TracerLess.h"
#endif

namespace libemb{
class TracerSink;
/**
 *  @class  Tracer
 *  @brief  调试跟踪类
 *  @note   用于程序调试
 */
class Tracer:public Singleton<Tracer>,public Runnable{
DECL_CLASSNAME(Tracer)
DECL_SINGLETON(Tracer)
public:
    ~Tracer();
    /**
     *  @brief  调试信息打印
     *  @param  level 打印级别
     *  @param  format 格式化字串
     *  @return void
     */
    void print(int level,const char* format,...);
    /**
     *  @brief  设置打印级别
     *  @param  level 打印级别
     *  @return void
     *  @note   默认打印级别为TRACE_LEVEL_INFO(不打印DBG信息)
     */
    void setLevel(int level);
    /**
     *  @brief  获取打印级别
     *  @param  void
     *  @return int 当前打印级别
     */
    int getLevel();
    /**
     * @brief 增加日志输出器
     * @param sink 
     */
    void addSink(std::shared_ptr<TracerSink> sink);
private:
    void run();
    void sinkMsg();
private:
	static const int TRACE_MAXLEN =4096;/* 打印长度最大为4096Bytes,超出后显示省略号 */
    Thread m_thread;
    Mutex m_logMutex;
    std::vector<std::string> m_logVect;
    int m_traceLevel{TRACE_LEVEL_INFO};
    std::vector<std::shared_ptr<TracerSink>> m_sinkVect;
};

class TracerSink{
DECL_CLASSNAME(TracerSink)
public:
    TracerSink()=default;
    virtual ~TracerSink()=default;
    /* 设置日志级别 */
    virtual void setLevel(int level){};
    /**
     * @brief 日志输出
     * @param uid 日志唯一标识(0~4:标准输出日志; 5~n:自定义日志,需使用TRACE_LOG输出)
     * @param msg 日志信息
     * @note 日志输出器可以根据uid来过滤要输出的日志,注意:sink方法中不能使用TRACE,否则会死锁!!!
     */
    virtual void sink(int uid, const std::string& msg)=0;
};

class STDSink:public TracerSink{
DECL_CLASSNAME(STDSink)
public:
    STDSink();
    virtual ~STDSink();
    void sink(int uid, const std::string& msg) override;
};

#if USE_ROS_LOG
class ROSSink:public TracerSink{
DECL_CLASSNAME(ROSSink)
public:
    ROSSink();
    virtual ~ROSSink();
    void setLevel(int level) override;
    void sink(int uid, const std::string& msg) override;
};
#endif
}
#endif



